package model;

/*
 * 
 * PlayerCharacter class
 * 
 * Contains attributes and location of the player character.
 * Also responsible for any vertical movement in game.
 * 
 */

public class PlayerCharacter {

	private int currentSprite = 0;
	private int health;
	private boolean facingRight = true;
	private int yPosition;
	// for jumpState: -1=Falling, 0=stable, 1=jumping, 2=DoubleJump
	private int jumpState;
	private int jumpCounter;
	private int jumpHeight = 6;
	private final int INVULNERABILITY = 5;
	private int invulnerabilityCount;
	// SpriteCount contains a value 0 and 3 to it will update the sprite
	// whenever the value is 0
	private int spriteCount;
	private static final int spriteChangeRate = 7;
	private static final int numberOfSprites = 8;

	/**
	 * PlayerCharacter
	 * 
	 * create a playerCharacter with an amount of health and a starting
	 * yPosition, gravity is also taken in but not used at this point
	 * 
	 * @param startingHealth
	 * @param startingYPosition
	 * @param currentGravity
	 */
	public PlayerCharacter(int startingHealth, int startingYPosition,
			int currentGravity) {
		health = startingHealth;
		yPosition = startingYPosition;
	}

	/**
	 * getFacing
	 * 
	 * returns facingRight boolean, true indicates right, false for left
	 * 
	 * @return
	 */
	public boolean getFacing() {
		return this.facingRight;
	}

	/**
	 * getHealth
	 * 
	 * returns the current amount of health that the playerCharacter has
	 * 
	 * @return
	 */
	public int getHealth() {
		return health;
	}

	/**
	 * getJumpHeight
	 * 
	 * returns the jumpHeight counter, which indicates how many clock cycles the
	 * playerCharacter will jump for
	 * 
	 * @return
	 */
	public int getJumpHeight() {
		return this.jumpHeight;
	}

	/**
	 * getJumpState
	 * 
	 * returns the current jumpState of the playerCharacter, 1 indicates
	 * jumping, 0 indicates stable, -1 indicates falling
	 * 
	 * @return
	 */
	public int getJumpState() {
		return this.jumpState;
	}

	/**
	 * getSprite
	 * 
	 * returns an integer indicating which sprite should currently be displayed
	 * 
	 * @return
	 */
	public int getSprite() {
		return this.currentSprite;
	}

	/**
	 * getYPosition
	 * 
	 * returns the current yPosition of the playerCharacter in pixels
	 * 
	 * @return
	 */
	public int getYPosition() {
		return this.yPosition;
	}

	/**
	 * isInvulnerabile
	 * 
	 * returns a boolean based upon whether or not the playerCharacter is
	 * currently invulnerable
	 * 
	 * @return
	 */
	public boolean isInvulnerabile() {
		if (invulnerabilityCount != 0) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Jump
	 * 
	 * sets the playerCharacter to the jumping state if is currently stable
	 * 
	 */
	public void Jump() {
		if (this.jumpState == 0) {
			this.jumpCounter = this.jumpHeight;
			this.jumpState = 1;
			return;
		}
	}

	/**
	 * setFacing
	 * 
	 * sets the direction the playerCharacter is currently facing, true means
	 * that he is facing right, false indicates left
	 * 
	 * @param facing
	 */
	public void setFacing(boolean facing) {
		this.facingRight = facing;
		return;
	}

	/**
	 * setJumpHeight
	 * 
	 * changes the length of game ticks that the playerCharacter jumps for
	 * 
	 * may become unnecessary as it probably won't be needed to change the jump
	 * height in the middle of a level
	 * 
	 * @param jumpHeight
	 */
	public void setJumpHeight(int jumpHeight) {
		this.jumpHeight = jumpHeight;
		return;
	}

	/**
	 * setJumpState
	 * 
	 * changes the current jumpState to the state that is passed in, 1 indicates
	 * jumping, 0 is stable, and -1 indicates falling
	 * 
	 * @param state
	 */
	public void setJumpState(int state) {
		this.jumpState = state;
		return;
	}

	/**
	 * setSprite
	 * 
	 * changes the currently used sprite
	 * 
	 * @param num
	 */
	public void setSprite(int num) {
		this.currentSprite = num;
		return;
	}

	/**
	 * setYPosition
	 * 
	 * changes the current yPosition of the playerCharacter (in pixels) should
	 * be between 0 and 700 as other values will cause the playerCharacter to
	 * die instantly
	 * 
	 * @param newYPosition
	 */
	public void setYPosition(int newYPosition) {
		this.yPosition = newYPosition;
	}

	/***
	 * will evaluate true it the character is still alive
	 * 
	 * if health points is a positive number it will be subtracted from
	 * currentHealth
	 ***/
	/**
	 * updateHealth
	 * 
	 * updates the health points of the playerCharacter, if it is a positive
	 * number it will be subtracted, it negative it will be added, ie healing
	 * him
	 * 
	 * @param healthPoints
	 * @return
	 */
	public boolean updateHealth(int healthPoints) {
		this.health -= healthPoints;
		if (this.health > 0) {
			this.invulnerabilityCount = this.INVULNERABILITY;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * updateinvulnerability
	 * 
	 * updates the invulnerability counter of the playerCharacter
	 */
	public void updateinvulnerability() {
		if (invulnerabilityCount != 0) {
			invulnerabilityCount--;
		}
		return;
	}

	/**
	 * updateJump
	 * 
	 * returns the playerCharacter's potential new yPosition based upon the
	 * jumpState and the jumpCounter, the returned integer is in pixels and is
	 * used for collision detection
	 * 
	 * @return
	 */
	public int updateJump() {
		if (jumpState == 0)
			return yPosition;
		else {
			if (jumpState == 1 || jumpState == 2) {
				jumpCounter--;
				if (jumpCounter == 0) {
					jumpState = -1;
					jumpCounter = jumpHeight;
					return yPosition;
				}
				switch (jumpCounter) {
				case (5):
					return yPosition - 50;
				case (4):
					return yPosition - 30;
				case (3):
					return yPosition - 20;
				case (2):
					return yPosition - 15;
				case (1):
					return yPosition - 12;
				default:
					return yPosition;
				}
			} else {
				if (jumpCounter > -10) {
					jumpCounter--;
				}
				return yPosition - jumpCounter;
			}
		}
	}

	/**
	 * updateSprite
	 * 
	 * updates the current sprite that will displayed to represent the
	 * playerCharaccter, it is done based upon what direction the
	 * playerCharacter is facing and what the previos sprite was
	 */
	public void updateSprite() {
		if (currentSprite < 0) {
			currentSprite = 7;
		}
		if (facingRight) {
			spriteCount++;
			spriteCount = spriteCount % spriteChangeRate;
			if (spriteCount == 0) {
				currentSprite++;
				currentSprite = currentSprite % numberOfSprites;
			}
		} else {
			spriteCount--;
			spriteCount = spriteCount % spriteChangeRate;
			if (spriteCount == 0) {
				currentSprite--;
				currentSprite = currentSprite % numberOfSprites;
			}
		}
	}
}